﻿// Decompiled with JetBrains decompiler
// Type: System.Web.Razor.Text.BufferingTextReader
// Assembly: System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: 682513D6-F37E-48AC-9909-F3EE103CFF14
// Assembly location: D:\Project\Idea\无人机外网\uav\客户端工程\排查工具\bin\Release\System.Web.Razor.dll

using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web.Razor.Resources;
using System.Web.Razor.Utils;

namespace System.Web.Razor.Text
{
  /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Provides a lookahead buffer for the text reader.</summary>
  public class BufferingTextReader : LookaheadTextReader
  {
    private Stack<BufferingTextReader.BacktrackContext> _backtrackStack = new Stack<BufferingTextReader.BacktrackContext>();
    private int _currentBufferPosition;
    private int _currentCharacter;
    private SourceLocationTracker _locationTracker;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Initializes a new instance of the <see cref="T:System.Web.Razor.Text.BufferingTextReader" /> class.</summary>
    /// <param name="source">The text reader for the buffer.</param>
    public BufferingTextReader(TextReader source)
    {
      this.InnerReader = source != null ? source : throw new ArgumentNullException(nameof (source));
      this._locationTracker = new SourceLocationTracker();
      this.UpdateCurrentCharacter();
    }

    internal StringBuilder Buffer { get; set; }

    internal bool Buffering { get; set; }

    internal TextReader InnerReader { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Gets or sets the current location of the character in the buffer.</summary>
    /// <returns>The current location of the character in the buffer.</returns>
    public override SourceLocation CurrentLocation => this._locationTracker.CurrentLocation;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Gets the current character in the buffer.</summary>
    /// <returns>The current character in the buffer.</returns>
    protected virtual int CurrentCharacter => this._currentCharacter;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Returns the current character from the buffer and advances the buffer position to the next character.</summary>
    /// <returns>The current character from the buffer.</returns>
    public override int Read()
    {
      int currentCharacter = this.CurrentCharacter;
      this.NextCharacter();
      return currentCharacter;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Returns the current character in the buffer.</summary>
    /// <returns>The current character in the buffer.</returns>
    public override int Peek() => this.CurrentCharacter;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Releases the unmanaged resources used by the current instance of this class, and optionally releases the managed resources.</summary>
    /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing)
        this.InnerReader.Dispose();
      base.Dispose(disposing);
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Begins the lookahead buffering operation for this <see cref="T:System.Web.Razor.Text.BufferingTextReader" />.</summary>
    /// <returns>A disposable action that ends the lookahead buffering.</returns>
    public override IDisposable BeginLookahead()
    {
      if (this.Buffer == null)
        this.Buffer = new StringBuilder();
      if (!this.Buffering)
      {
        this.ExpandBuffer();
        this.Buffering = true;
      }
      BufferingTextReader.BacktrackContext context = new BufferingTextReader.BacktrackContext()
      {
        BufferIndex = this._currentBufferPosition,
        Location = this.CurrentLocation
      };
      this._backtrackStack.Push(context);
      return (IDisposable) new DisposableAction((Action) (() => this.EndLookahead(context)));
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Discards the backtrack context associated the lookahead buffering operation.</summary>
    public override void CancelBacktrack()
    {
      if (this._backtrackStack.Count == 0)
        throw new InvalidOperationException(RazorResources.CancelBacktrack_Must_Be_Called_Within_Lookahead);
      this._backtrackStack.Pop();
    }

    private void EndLookahead(BufferingTextReader.BacktrackContext context)
    {
      if (this._backtrackStack.Count <= 0 || this._backtrackStack.Peek() != context)
        return;
      this._backtrackStack.Pop();
      this._currentBufferPosition = context.BufferIndex;
      this._locationTracker.CurrentLocation = context.Location;
      this.UpdateCurrentCharacter();
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Advances the buffer position to the next character.</summary>
    protected virtual void NextCharacter()
    {
      int currentCharacter = this.CurrentCharacter;
      if (currentCharacter == -1)
        return;
      if (this.Buffering)
      {
        if (this._currentBufferPosition >= this.Buffer.Length - 1)
        {
          if (this._backtrackStack.Count == 0)
          {
            this.Buffer.Length = 0;
            this._currentBufferPosition = 0;
            this.Buffering = false;
          }
          else if (!this.ExpandBuffer())
            this._currentBufferPosition = this.Buffer.Length;
        }
        else
          ++this._currentBufferPosition;
      }
      else
        this.InnerReader.Read();
      this.UpdateCurrentCharacter();
      this._locationTracker.UpdateLocation((char) currentCharacter, (char) this.CurrentCharacter);
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Reads the next character from the text reader and appends it to the lookahead buffer.</summary>
    /// <returns>true if a character was read from the text reader; otherwise, false.</returns>
    protected bool ExpandBuffer()
    {
      int num = this.InnerReader.Read();
      if (num == -1)
        return false;
      this.Buffer.Append((char) num);
      this._currentBufferPosition = this.Buffer.Length - 1;
      return true;
    }

    private void UpdateCurrentCharacter()
    {
      if (this.Buffering && this._currentBufferPosition < this.Buffer.Length)
        this._currentCharacter = (int) this.Buffer[this._currentBufferPosition];
      else
        this._currentCharacter = this.InnerReader.Peek();
    }

    private class BacktrackContext
    {
      public int BufferIndex { get; set; }

      public SourceLocation Location { get; set; }
    }
  }
}
